#!/usr/bin/env python3.3

import re
import sys
import os
import logging
import brickred.net


def init_logger():
    logging.basicConfig(
        format='%(asctime)s[%(levelname)s] %(message)s',
        datefmt='[%Y-%m-%d %H:%M:%S]',
        level=logging.DEBUG)


def login(hc):
    logging.info('login start')
    url = 'http://hentaiverse.org'
    doc = hc.request(url)

    def has_login_form(tag):
        if (tag.name == 'form' and tag.has_attr('name') and
                tag['name'] == 'ipb_login_form'):
            return True
        else:
            return False
    login_form = doc.find(has_login_form)

    if login_form is not None:
        ipb_login_username = input('username:')
        ipb_login_password = input('password:')
        doc = hc.request(login_form['action'], 'post', {
            'ipb_login_username': ipb_login_username,
            'ipb_login_password': ipb_login_password
        })
        if doc.find('p', text='This page requires you to log on.'):
            logging.error('Login Failed')

    logging.info('login success')


######################################################################
# magic
######################################################################
def cast_regen(hc, game_url):
    logging.info('Cast Regen')
    hc.request(game_url, 'post', {
        'battle_subattack': 312,
        'battle_target': 0,
        'battle_targetmode': 'magic',
        'battleaction': 1
    })


def cast_spark_of_life(hc, game_url):
    logging.info('Cast SparkOfLife')
    hc.request(game_url, 'post', {
        'battle_subattack': 422,
        'battle_target': 0,
        'battle_targetmode': 'magic',
        'battleaction': 1
    })


def cast_heartseeker(hc, game_url):
    logging.info('Cast Heartseeker')
    hc.request(game_url, 'post', {
        'battle_subattack': 431,
        'battle_target': 0,
        'battle_targetmode': 'magic',
        'battleaction': 1
    })


def cast_cure(hc, game_url):
    logging.info('Cast Cure')
    hc.request(game_url, 'post', {
        'battle_subattack': 311,
        'battle_target': 0,
        'battle_targetmode': 'magic',
        'battleaction': 1
    })


def cast_full_cure(hc, game_url):
    logging.info('Cast FullCure')
    hc.request(game_url, 'post', {
        'battle_subattack': 313,
        'battle_target': 0,
        'battle_targetmode': 'magic',
        'battleaction': 1
    })


######################################################################
# item
######################################################################
def use_item(hc, game_url, pos):
    logging.info('Use Item {}'.format(pos))
    hc.request(game_url, 'post', {
        'battle_subattack': pos,
        'battle_target': 0,
        'battle_targetmode': 'items',
        'battleaction': 1
    })


######################################################################
# physical attack
######################################################################
def cast_physical_attack(hc, game_url, pos):
    logging.info('Cast Physical Attack')
    hc.request(game_url, 'post', {
        'battle_subattack': 0,
        'battle_target': pos,
        'battle_targetmode': 'attack',
        'battleaction': 1
    })


######################################################################
# game helper
######################################################################
def get_attack_pos(hc, game_url):
    logging.info('Find Attack Pos')
    doc = hc.request(game_url)
    monsterpane = doc.find(id='monsterpane')

    if monsterpane is None:
        logging.info('Monsterpane Not Found')
        return -1

    monster_list = monsterpane.find_all('div', class_='btm1')
    alive_cnt = 0
    attack_pos = -1
    for i in range(len(monster_list)):
        if monster_list[i].has_attr('onclick'):
            alive_cnt += 1
            if attack_pos == -1:
                attack_pos = i + 1
    logging.info('Alive Count: %d, Next Attack Pos %d',
                 alive_cnt, attack_pos)
    return attack_pos


def get_value_from_digit_list(digit_list):
    l = []
    for digit_node in digit_list:
        digit = digit_node['class'][1][2:]
        if len(digit) == 1:
            l.append(digit)
        else:
            break
    return int(''.join(l))


def get_game_state(hc, game_url):
    doc = hc.request(game_url)

    if (doc.find(id='healthflash')):
        hp_digit_list = doc.body.\
            find('div', class_='stuffbox csp').\
            find('div', class_='cwbdv').\
            find('div', class_='fd2').\
            find_all('div', class_='f2rr')
    else:
        hp_digit_list = doc.body.\
            find('div', class_='stuffbox csp').\
            find('div', class_='cwbdv').\
            find('div', class_='fd2').\
            find_all('div', class_='f2ry')
    hp_digit_list.reverse()
    hp_value = get_value_from_digit_list(hp_digit_list)

    mp_digit_list = doc.body.\
        find('div', class_='stuffbox csp').\
        find('div', class_='cwbdv').\
        find_next_sibling('div', class_='cwbdv').\
        find('div', class_='fd2').\
        find_all('div', class_='f2ry')
    mp_digit_list.reverse()
    mp_value = get_value_from_digit_list(mp_digit_list)

    return {
        'hp_value': hp_value,
        'mp_value': mp_value
    }


######################################################################
def recover_all(hc):
    logging.info('Recover All')
    game_url = 'http://hentaiverse.org/?login=1'
    hc.request(game_url, 'post', {
        'recover': 'all',
    })


def do_hv_event(hc):
    logging.info('move to e-hentai.org for find a random event')
    url = 'http://www.e-hentai.org'
    doc = hc.request(url)

    eventpane = doc.find(id='eventpane')

    if eventpane is None:
        logging.info('Do not find a random event')
        return

    if eventpane.find('a') is None:
        logging.info('A New Day Begin!')
        return

    ret = re.match("window.open\('(.*?)',", eventpane.a['onclick'])
    url = ret.group(1)
    hc.request(url)

    game_url = 'http://hentaiverse.org/?login=1'

    pos = get_attack_pos(hc, game_url)
    if pos == -1:
        return
    cast_heartseeker(hc, game_url)
    cast_spark_of_life(hc, game_url)
    cast_regen(hc, game_url)

    mana_potion_pos = 1
    can_use_full_cure = True
    can_use_mana_potion = True
    turn_count_buff = 0
    turn_count_full_cure = 0
    turn_count_mana_potion = 0
    while True:
        pos = get_attack_pos(hc, game_url)
        if pos == -1:
            return
        cast_physical_attack(hc, game_url, pos)
        game_state = get_game_state(hc, game_url)
        #hp
        if game_state['hp_value'] < 5000 and can_use_full_cure:
            cast_full_cure(hc, game_url)
            can_use_full_cure = False
        elif game_state['hp_value'] < 10000:
            cast_cure(hc, game_url)
        #mp
        if game_state['mp_value'] < 700 and can_use_mana_potion:
            use_item(hc, game_url, mana_potion_pos)
            mana_potion_pos += 1
            can_use_mana_potion = False

        turn_count_buff += 1
        if not can_use_full_cure:
            turn_count_full_cure += 1
        if not can_use_mana_potion:
            turn_count_mana_potion += 1

        if (turn_count_buff > 50):
            turn_count_buff = 0
            cast_regen(hc, game_url)
            cast_spark_of_life(hc, game_url)
        if (turn_count_full_cure > 10):
            turn_count_full_cure = 0
            can_use_full_cure = True
        if (turn_count_mana_potion > 20):
            turn_count_mana_potion = 0
            can_use_mana_potion = True


# main
def main():
    init_logger()

    script_path = os.path.dirname(sys.argv[0])
    hc = brickred.net.HTTPClient(
        'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/18.0',
        script_path + '/hv.cookie')

    login(hc)
    recover_all(hc)
    do_hv_event(hc)
    hc.save_cookie()


if __name__ == '__main__':
    main()
